package com.tyk.bookstore.front.order.strategy.split.impl;


import com.tyk.bookstore.front.common.core.util.AssertUtil;
import com.tyk.bookstore.front.order.model.result.OrderResultEnum;
import com.tyk.bookstore.front.order.strategy.split.OrderSplitAction;
import com.tyk.bookstore.front.order.strategy.split.model.SplitDto;
import com.tyk.bookstore.front.order.strategy.split.model.SplitStock;
import com.tyk.bookstore.front.order.util.MapStructOrder;
import com.tyk.bookstore.front.storage.model.dto.StockMeetDto;
import com.tyk.bookstore.front.storage.service.StockApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description MinPackageStrictSplitAction
 */
@Component
@RequiredArgsConstructor
public class MinPackageStrictSplitAction implements OrderSplitAction {

    private final StockApiService stockApiService;
    private final MapStructOrder mapStructOrder;

    @Override
    public List<SplitDto> split(Long cneeAddId, List<SplitStock> splitStockList) {

        // 严格满足要求的库存记录
        List<StockMeetDto> stockMeetList = stockApiService.getStockMeetListWithStrict(
                mapStructOrder.toStock4OrderStockMeetQueryList(splitStockList)
        );

        // 检查是否所需的所有书籍均严格满足库存
        long bookCountHave = stockMeetList.stream().mapToLong(StockMeetDto::getBookId).distinct().count();
        AssertUtil.equal(bookCountHave, (long) splitStockList.size(), OrderResultEnum.STOCK_NOT_MEET);


        // bookId=>num 映射
        Map<Long, Long> idMapNum = splitStockList.stream().collect(Collectors.toMap(SplitStock::getBookId, SplitStock::getNum));

        // 需要的商品的ID
        Set<Long> bookIdSetNeed = splitStockList.stream().map(SplitStock::getBookId).collect(Collectors.toSet());


        // warehouseId=>bookIdSet   映射
        Map<Long, Set<Long>> wbsMap = stockMeetList.stream().collect(
                Collectors.groupingBy(
                        StockMeetDto::getWarehouseId,
                        Collectors.mapping(StockMeetDto::getBookId, Collectors.toSet())
                )
        );


        // 选择仓库
        List<SplitDto> sdList = new ArrayList<>();
        while (!bookIdSetNeed.isEmpty()) {
            // 找到可发商品数量最多的仓库
            Map.Entry<Long, Set<Long>> me = wbsMap.entrySet().stream().max(Comparator.comparingInt(x -> x.getValue().size())).get();

            // 拷贝数据
            Long warehouseId = me.getKey();
            HashSet<Long> bookIdSet = new HashSet<>(me.getValue());


            // 商品bookIdSet从仓库warehouseId中发出
            sdList.add(new SplitDto(
                    warehouseId,
                    bookIdSet.stream().map(bookId -> new SplitDto.Stock(bookId, idMapNum.get(bookId))).toList()
            ));

            // 将bookIdSet中的商品从bookIdSetNeed中移除
            bookIdSetNeed.removeAll(bookIdSet);

            // 将bookIdSet中的商品从各仓库候选中移除
            wbsMap.forEach((k, v) -> v.removeAll(bookIdSet));
            // 移除无候选商品的仓库
            wbsMap.values().removeIf(Set::isEmpty);
        }

        // 返回拆分结果
        return sdList;
    }

}
